#include "Goose.h"

#include "Util.h"
#include "goose_publisher.h"
#include "iec61850_model.h"
#include "mms_value.h"

#include <goose_subscriber.h>
#include <utility>
int num = 0;

Goose::Goose(std::string interface) {

    gooseCommParameters.appId = 0x1000;

    gooseCommParameters.dstAddress[0] = 0x01;
    gooseCommParameters.dstAddress[1] = 0x0c;
    gooseCommParameters.dstAddress[2] = 0xcd;
    gooseCommParameters.dstAddress[3] = 0x01;
    gooseCommParameters.dstAddress[4] = 0x00;
    gooseCommParameters.dstAddress[5] = 0x01;
    gooseCommParameters.vlanId        = 0;
    gooseCommParameters.vlanPriority  = 4;

    this->interface = interface;

    pubMaps.clear();
}

Goose::~Goose() {
    for (auto it = pubMaps.begin(); it != pubMaps.end(); it++) {
        GoosePublisher publisher = it->first;
        LinkedList     list      = it->second;

        GoosePublisher_destroy(publisher);
        // LinkedList_destroy(list);
    }

    GooseReceiver_stop(receiver);

    GooseReceiver_destroy(receiver);
}


void Goose::Subscribe() {
    receiver = GooseReceiver_create();

    GooseReceiver_setInterfaceId(receiver, interface.c_str());
    zlog_i("Goose Subscribe 绑定端口: %s", interface.c_str());

    GooseSubscriber subscriber = GooseSubscriber_create("", NULL);
    GooseSubscriber_setObserver(subscriber);
    uint8_t dstMac[6] = {0x01, 0x0c, 0xcd, 0x01, 0x00, 0x01};

    GooseSubscriber_setDstMac(subscriber, dstMac);
    GooseSubscriber_setAppId(subscriber, 0x1000);

    GooseSubscriber_setListener(subscriber, GooseListener, NULL);

    GooseReceiver_addSubscriber(receiver, subscriber);
    GooseReceiver_start(receiver);
}

void Goose::GooseListener(GooseSubscriber subscriber, void *parameter) {
    zlog_i("GooseListener");
    printf("GOOSE event:\n");
    printf("  stNum: %u sqNum: %u\n",
           GooseSubscriber_getStNum(subscriber),
           GooseSubscriber_getSqNum(subscriber));
    printf("  timeToLive: %u\n",
           GooseSubscriber_getTimeAllowedToLive(subscriber));

    uint64_t timestamp = GooseSubscriber_getTimestamp(subscriber);

    printf("  timestamp: %u.%u\n",
           (uint32_t)(timestamp / 1000),
           (uint32_t)(timestamp % 1000));
    printf("  message is %s\n",
           GooseSubscriber_isValid(subscriber) ? "valid" : "INVALID");

    MmsValue *values = GooseSubscriber_getDataSetValues(subscriber);
    if (values == NULL) {
        zlog_i("values is NULL");
        return;
    }

    if (values != NULL) {
        Goose::ParseMmsValueFromGoose(values);
    }

    char buffer[1024];

    MmsValue_printToBuffer(values, buffer, 1024);

    printf("  allData: %s\n", buffer);
}

void Goose::ParseMmsValueFromGoose(MmsValue *value) {
    int       mmsType    = MmsValue_getType(value);
    int       stringSize = 0;
    int       len        = 0;
    MmsValue *ele;

    if (value == NULL) {
        zlog_i("values is null");
        return;
    }

    zlog_i("values mmsType: %d", mmsType);
    switch (MmsValue_getType(value)) {
        case MMS_ARRAY:
        case MMS_STRUCTURE:
            len = MmsValue_getArraySize(value);
            zlog_i("MMS Array Size: %d", len);
            zlog_i("MMS_ARRAY  || MS_STRUCTURE");
            for (int i = 0; i < len; i++) {
                ele = MmsValue_getElement(value, i);
                if (ele == NULL) {
                    zlog_i("ele is null");
                    return;
                }
                zlog_i("value MmsType: %d", MmsValue_getType(ele));
                ParseMmsValueFromGoose(ele);
            }
            break;
        case MMS_BOOLEAN:
            zlog_i("MMS_BOOLEAN");
            zlog_i("value: %d", MmsValue_getBoolean(value));
            break;
        case MMS_BIT_STRING:
            zlog_i("MMS_BIT_STRING");
            zlog_i("value: %d", MmsValue_getBitStringAsInteger(value));
        case MMS_INTEGER:
            zlog_i("MMS_INTEGER");
            zlog_i("value: %d", MmsValue_toInt32(value));
            break;
        case MMS_UNSIGNED:
            zlog_i("MMS_UNSIGNED");
            zlog_i("value: %u", MmsValue_toUint32(value));
            break;
        case MMS_FLOAT:
            zlog_i("MMS_FLOAT");
            zlog_i("value: %f", MmsValue_toFloat(value));
            break;
        case MMS_OCTET_STRING:
            zlog_i("MMS_OCTET_STRING");
            stringSize = MmsValue_getOctetStringSize(value);
            zlog_i("string len: %d, value: %s",
                   stringSize,
                   MmsValue_getOctetStringBuffer(value));
            break;
        case MMS_VISIBLE_STRING:
        case MMS_STRING:
            zlog_i("MMS_VISIBLE_STRING");
            stringSize = MmsValue_getStringSize(value);
            zlog_i("string len: %d, value: %s",
                   stringSize,
                   MmsValue_toString(value));
            break;
        case MMS_UTC_TIME:
            zlog_i("MMS_UTC_TIME");
            zlog_i("value: %d", MmsValue_toUnixTimestamp(value));
            break;
        case MMS_BINARY_TIME:
            zlog_i("MMS_BINARY_TIME");
            zlog_i("value: %lx", MmsValue_getBinaryTimeAsUtcMs(value));
            break;
        default:
            zlog_i("未知数据类型, type: %d", MmsValue_getType(value));
            break;
    }

    return;
}

void Goose::Observer() {
    GooseSubscriber_setObserver(subscriber);
    GooseSubscriber_setListener(subscriber, GooseListener, NULL);
}
